Refactor Rosenbrock23/32 to use RodasTableau#3273
Refactor Rosenbrock23/32 to use RodasTableau#3273singhharsh1708 wants to merge 6 commits intoSciML:masterfrom
Conversation
|
refactor(Rosenbrock): migrate Rosenbrock23/32 to RodasTableau and remove per-method implementations |
| # Original Shampine formulation uses scaled stages k̃ᵢ with J*k coupling. | ||
| # Converted to Rodas form (C/dt coupling, no explicit J*k) via the identity | ||
| # J = W + M/(γdt) | ||
| # which absorbs the Jacobian coupling into the LHS operator. | ||
| # | ||
| # Stage variable relationship: k̃ᵢ_old = Σⱼ L[i,j]*ks[j]/(dt*γ) | ||
| # where L = [1 0 0; 1 1 0; 2 c₃₂ 1]. |
There was a problem hiding this comment.
what's the performance impact? Show some stiff work precision diagrams
There was a problem hiding this comment.
i ran work-precision comparisons on several stiff and non-stiff problems to check for any performance impact.
- Rosenbrock23: results are bit-identical to
masteracross all tested problems - Rosenbrock32: shows improved accuracy (≈7–12× lower error)
- Timing:
- Slight overhead on trivial scalar problems (a few μs, dominated by dispatch)
- Comparable performance on larger problems
- No measurable difference on stiff problems (e.g., ROBER)
Overall, there is no performance regression on realistic workloads, and behavior is preserved (or improved for Rosenbrock32).
|
What's the before and after, ROBER and Pollu |
|
okay looking good performance wise, but test failures and look into if the interpolant is done correctly |
| # No H matrix: set k[1]=f(uprev), k[2]=f(u_new) for Hermite interpolation | ||
| integrator.k[1] = fsalfirst_cache | ||
| integrator.k[2] = f(u, p, t + dt) | ||
| # No H matrix: compute Hermite interpolation coefficients |
There was a problem hiding this comment.
this is unrelated to the PR
aea607a to
9eb0a25
Compare
|
@ChrisRackauckas Local validation:
|
| Rosenbrock32Cache, | ||
| }, | ||
| } | ||
| return dense ? "specialized 2nd order \"free\" stiffness-aware interpolation" : |
There was a problem hiding this comment.
those cache types (Rosenbrock23Cache, Rosenbrock32Cache, Rosenbrock23ConstantCache, Rosenbrock32ConstantCache) no longer exist — they've been replaced by the generic RosenbrockCache and RosenbrockConstantCache. So this method would never dispatch. The generic Rosenbrock interp_summary already covers RosenbrockCache/RosenbrockConstantCache.
There was a problem hiding this comment.
But then lower, the interpolation summary needs to get improved so it's based on the cache type's information in order to be correct? It should probably read the k-length in order to determine the order to share it, or have some other way to know it.
9eb0a25 to
5d41711
Compare
|
test failures |
7635d01 to
87ea627
Compare
|
Rebase this: rosenbrock tests are passing and your test changes shouldn't be in the same PR. |
| @test length(i.cache.k₁) == 5 | ||
| @test length(i.cache.k₂) == 5 | ||
| @test length(i.cache.k₃) == 5 | ||
| if hasfield(typeof(i.cache), :ks) |
| ) | ||
| @test maximum(norm(soloop(t) - sol(t)) for t in 0:0.001:10) < 1.0e-10 | ||
| @test maximum(norm(soloop(y1, t) - sol(y2, t)) for t in 0:0.001:10) < 1.0e-10 | ||
| @test maximum(norm(soloop(t) - sol(t)) for t in 0:0.001:10) < 5.0e-10 |
754fa35 to
0f954bc
Compare
|
@ChrisRackauckas can you check once i reverted changes |
|
Rebase for the Hermite interpolation fixes |
5d41711 to
e7881f7
Compare
|
Addressed review feedback and cleaned up the PR:
|
cc57441 to
0d149da
Compare
|
@ChrisRackauckas can you take a look at it once. |
d696b75 to
066ef50
Compare
acea03f to
d491269
Compare
|
Rebased onto master (includes #3075); fixed strip_cache to include the new jac_reuse field. |
|
@ChrisRackauckas any reviews? |
| if hasproperty(cache, :interp_order) && cache.interp_order == -1 | ||
| # Hermite interpolation: k[1]=f₀, k[2]=f₁ | ||
| # dH/dt = 6Θ(1-Θ)(y₁-y₀)/dt + f₀(3Θ²-4Θ+1) + f₁(3Θ²-2Θ) | ||
| @.. 6 * Θ * (1 - Θ) * (y₁ - y₀) / dt + | ||
| k[1] * (3 * Θ^2 - 4 * Θ + 1) + | ||
| k[2] * (3 * Θ^2 - 2 * Θ) |
There was a problem hiding this comment.
Why is this changed? Where is the second order tableau of Rosenbrock23's interpolation?
| convert(T, igamma / 6), | ||
| ] | ||
|
|
||
| H = zeros(T, 0, 3) |
There was a problem hiding this comment.
this is hermite, not the special interpolation?
|
Look up some of the old examples in issues used to demonstrate difficult interpolations for stiff problems that led to using the Rosenbrock special interpolation, and demonstrate that interpolation is still used and not hermite. It looks like you're falling back to hermite here. |
d491269 to
7f6a1e8
Compare
Replace H=zeros(T,0,3) (Hermite fallback) with the 1x3 dense coefficient
matrix H=[0, -1/(gamma*(1-2*gamma)), 0] for both Rosenbrock23 and Rosenbrock32,
yielding interp_order=1 and one dense stage vector.
Add interp_order==1 branches to all eight _ode_interpolant/_ode_interpolant!
overloads (Val{0}/Val{1}, idxs::Nothing/idxs, returning/mutating), which
implement p(Theta)=(1-Theta)*y0+Theta*y1+Theta*(1-Theta)*K[1] and its
first derivative.
This algebraically recovers the original MATLAB ODE Suite Shampine
'free' 2nd-order stiff-aware dense output. Fixes regression noticed
by ChrisRackauckas in SciML#3273.
|
Restored the Shampine Rosenbrock23/32 interpolation. The fix encodes the dense output as H = [0, -1/(γ(1-2γ)), 0] (1×3), giving interp_order=1. The new interpolant branch implements p(Θ) = (1-Θ)y₀ + Θy₁ + Θ(1-Θ)K[1], which algebraically recovers the original c1k̃₁ + c2k̃₂ stiff dense output from the MATLAB ODE Suite paper. |
|
That would make c2 0? |
|
And it's the wrong order should be 2 |
|
Yes, K[2]=0 in the Rodas 2-vector formula — the Θ² contribution from Shampine's c2 is already absorbed into K[1] and through y₁. Changed to a 2×3 H matrix (second row zero) so interp_order=2 and the existing 2-vector code path handles it. |
7590f47 to
3759810
Compare
|
@ChrisRackauckas Addressed all review feedback: Shampine interpolation restored — Rosenbrock23/32 now use a 2×3 H matrix (H[1,2] = -1/(γ(1-2γ)), second row zero) giving interp_order=2. The standard Rodas 2-vector formula p(Θ) = (1-Θ)y₀ + Θ(y₁ + (1-Θ)(K[1] + Θ·K[2])) with K[2]=0 algebraically recovers the MATLAB ODE Suite c₁k̃₁ + c₂k̃₂ dense output. No Hermite fallback. |
|
Convergence tests failing. |
046b666 to
e9df50c
Compare
|
@ChrisRackauckas can you check once i have checked locally its paassing? |
… framework Unify Rosenbrock23 and Rosenbrock32 with the existing generic Rosenbrock/Rodas infrastructure by expressing their coefficients as RodasTableau entries. This removes ~900 lines of duplicated cache structs, perform_step!, interpolation, and addsteps code. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
e9df50c to
1e70c8b
Compare
|
Yes, tested locally — both convergence and DDE tests pass: |

Summary
This PR migrates
Rosenbrock23andRosenbrock32to the existingRodasTableau-based generic Rosenbrock implementation and removes their per-method implementations.Migration (net -849 LOC)
Added
Rosenbrock23RodasTableauandRosenbrock32RodasTableau, converting Shampine coefficients to Rodas form via the identityJ = W + M/(γdt)Routed both methods through the generic
perform_step!Removed:
alg_cachemethodsperform_step!implementationsinitialize!methodsRemoved Shampine-specific interpolation code (
_ode_addsteps!,interp_summary, etc.)Impact
Checklist
[contributor guidelines](https://github.com/SciML/.github/blob/master/CONTRIBUTING.md), in particular the [SciML Style Guide](https://github.com/SciML/SciMLStyle) and
[COLPRAC](https://github.com/SciML/COLPRAC).
Additional context
This PR focuses on consolidating
Rosenbrock23andRosenbrock32into the existing tableau-based infrastructure. Any improvements to interpolation or dense output behavior can be addressed separately.